% -----------------------------------------------------------
% Proyecto 1 - Lógica para Ciencias de la Computación 2013
%	   Juego GO. Implementación en Prolog.
%
% Comisión 8:
%             De Miguel, Agustina. LU: 99947.
%             Hubert, Rocío. LU: 99282.
%
% Representación del tablero:
%		             Se representan las paredes del tablero como
% pared(Fila, Columna), donde las paredes son las que tienen fila o
% columna 0, o bien, fila o columna 19.
%		             Se representan las posiciones ocupadas por
% alguna ficha con hechos del tipo pos(Fila, Columna, Color), donde
% Color puede ser b o n, representando fichas blancas o negras
% respectivamente.
%		     Las posiciones vacías no se representan.
%
% Los números se encuentran en notación s^n(0).
%
% ------------------------------------------------------------

%    Se declara al predicado pos/3 dinámico, ya que será añadido o
% retirado del programa dinámicamente, por medio de los predicados
% assert/1 y retract/1.
%
% Predicado pos/3. Indica que en la posicion (Fila, Columna) se
% encuentra una ficha Color.
%
% pos(+Fila, +Columna, +Color).
:- dynamic pos/3.

% Predicado pared/2.
%
% Representa las paredes del tablero. Las paredes serán las que tengan
% fila o columna 0, o bien, fila o columna 20. Los números se encuentran
% en notación s^n(0).
%
% pared(+Fila, +Columna).

pared(0, _).
pared(_, 0).
pared(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(0)))))))))))))))))))) ,_).
pared(_, s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(0)))))))))))))))))))) ).


% Predicado agregar/5.
% Dadas una fila X, una columna Y y un color C, determina si esa ficha C se
% puede agregar al tablero en la posición (X, Y).
% Si cumple las condiciones para ser agregada al tablero, se incorporará mediante el predicado assert/1.
% Si al agregar esa ficha al tablero, se encierra a otras del color
% contrario, devuelve la cantidad de fichas encerradas (lo que se
% traduce al puntaje).
% También devuelve la configuración actual del tablero.
%
% Requiere que los números de Fila y Columna estén en notación s^n(0).
%
% agregar(+Fila, +Columna, +Color, -Puntaje, -Config).

agregar(X, Y, C, P, Conf):- vacio(X,Y), assert(pos(X,Y,C)), quedanEncerrados(X,Y,C,A), contar(A,N), N\=0, eliminarPosiciones(A), pasarAN(N,P), config(Conf).
agregar(X, Y, C, 0, Conf):- not(suicidio(X,Y,C)), config(Conf).


% Predicado quedanEncerrados/4.
% Determina si la ficha CC, en la posición (X, Y), encierra a fichas del color contrario en   
% todas las direcciones: arriba, abajo, izquierda y derecha. Devuelve 
% una lista con las fichas del color contrario encerradas.
%
% quedanEncerrados(+X, +Y, +CC, -Rodeados)

quedanEncerrados(s(X),s(Y),CC,A):- contrario(CC,C),
	quedoEncerrado(s(s(X)), s(Y), C ,L1),
	quedoEncerrado(X, s(Y), C,L2), append(L1,L2,LL2),
	quedoEncerrado(s(X), s(s(Y)), C,L3), append(LL2,L3,LL3),
	quedoEncerrado(s(X), Y, C, L4), append(LL3,L4,LL4),
	minimizar(LL4,LL5), acomodar(C,LL5,A).
   

%Predicado quedoEncerrado/4.
%
% Dada una fila X, una columna Y y un color C, determina si se encuentra encerrada. En caso de ser 
% verdadero, devuelve en la lista Z todos los pares rodeados. Si no es así, devuelve una lista vacía.
%
% quedoEncerrado(+X,+Y,+C,-Z)

quedoEncerrado(X,Y,C,Z): -encerrados(X,Y,C,[],Z).
quedoEncerrado(X,Y,C,[]).


% Predicado encerrados/5.
%
% Dada una posición según X e Y, un color C y una lista L de elementos que se encuentran encerrados,
% determina si la ficha se encuentra encerrada con ayuda de la consulta auxiliar encerrado/5.
% (Con respecto a derecha,izquierda, abajo y arriba).
% En caso afirmativo, devuelve en R una lista con las posiciones descubiertas como encerradas unidas a los elementos recibidos anteriormente.
%
%
%encerrados(+X,+Y,+C,+LL0,-LL5).

encerrados( s(X), s(Y), C, L, R) :-  pos(s(X),s(Y),C),
    encerrado( s(s(X)), s(Y), C, [ p(s(X),s(Y)) | L], L1),
    append( [ p(s(X),s(Y)) | L ], L1,LL1),
    encerrado( X, s(Y), C, LL1, L2), append(LL1,L2,LL2),
    encerrado( s(X), s(s(Y)), C, LL2, L3), append(LL2,L3,LL3),
    encerrado( s(X), Y, C, LL3, L4), append(LL3,L4,LL4), minimizar(LL4,R).


% Predicado encerrado/5
% 
% Determina si una ficha de color C, en la posición (X, Y) y con una lista de fichas rodeadas, se
% encontraría encerrada. Si es así, devuelve una lista de las fichas que están rodeadas.
% 
% encerrado(+X, +Y, +C, +LVA, -LVD)

encerrado(X, Y, _, _, []):- pared(X, Y).
encerrado(X, Y, C, _, []):- hayContrario(X, Y, C).
encerrado(X, Y, C, LVA, []):- pos(X,Y,C), pertenece( p(X,Y), LVA).
encerrado(X, Y, C, LVA, [ p(X,Y) | LVD ]):- pos(X,Y,C), noPertenece( p(X,Y), LVA), encerrados(X, Y, C,[ p(X,Y) | LVA], LVD).


% Predicado suicidio/3.
%
% Dada una fila X, una columna Y y un color C, evalúa si resulta en suicidio
% insertar una piedra de color C en la posición (X,Y) del tablero.
% Si no resulta en suicidio entonces la piedra queda ingresada.
%
% suicidio(+X,+Y,+C).

suicidio(X,Y,C):- encerrados(X, Y, C, [], _),  retract(pos(X,Y,C)).



% Predicado auxiliar hayContrario/3.
%
% Dadas una posición (X, Y) y un color C, determina si en esa posición
% (X, Y) se encuentra una ficha del color contrario a C.
%
% hayContrario(+Fila, +Columna, +Color).

hayContrario(X, Y, b):- pos(X, Y, n).
hayContrario(X, Y, n):- pos(X, Y, b).


% Predicado eliminarPosiciones/1.
%
% Dada una lista de las posiciones pos(Fila, Columna, Color) ,
% las elimina del tablero usando el predicado retractall/1.
%
% eliminarPosiciones(+L).

eliminarPosiciones([]).
eliminarPosiciones([ pos(X,Y,C) | T ]):- eliminarPosiciones(T), retractall(pos(X,Y,C)).


% Predicado auxiliar config/1.
%
% Devuelve una lista con la posiciones pos(X, Y, C), donde X es el número
% de fila; Y, de columnas y C el color de la ficha. Es decir, devuelve
% la configuración actual del tablero (las posiciones ocupadas).
%
% La lista que devuelve tiene los números en notación natural.
%
% config(-Posiciones).

config(Z):- findall(pos(X,Y,C), (pos(X1,Y1,C), pasarAN(X1,X), pasarAN(Y1,Y)), Z).


% Predicado resetear/0.
%
% Se encarga de vaciar todo el tablero, borrando todas las posiciones ocupadas del mismo.
%

resetear:- findall(pos(X,Y,C), pos(X,Y,C), Z), eliminarPosiciones(Z).




% Predicados auxiliares varios.

% Predicado auxiliar contrario/2.
%
% Dado un color C, devuelve el color contrario a C.
%
% contrario(+C, -Contrario).

contrario(b, n).
contrario(n, b).


% Predicado auxiliar pertenece/2.
%
% Dado un elemento X y una lista L, determina si el elemento X pertenece
% a L.
%
% pertenece(+Elemento, +Lista).

pertenece(X, [X|_]).
pertenece(X, [H|T]):- H\=X, pertenece(X, T).


% Predicado auxiliar noPpertenece/2.
%
% Dado un elemento X y una lista L, determina si el elemento X no pertenece
% a L.
%
% noPertenece(+Elemento, +Lista).

noPertenece(_,[]).
noPertenece(X,[Y|Ys]):- X\=Y, noPertenece(X,Ys).


% Predicado minimizar/2.
%
% La segunda lista contiene los elementos de la primera, pero ésta no tiene repeticiones.
%
% minimizar(+Lista,-ListaMinimizada)

minimizar([],[]).
minimizar([X|XS],[X|Y]):- noPertenece(X,XS), minimizar(XS,Y).
minimizar([X|XS],Y):- pertenece(X,XS), minimizar(XS,Y).


% Predicado auxiliar vacio/2.
%
% Dado una fila X y una columna Y, determina si esa posición se
% encuentra vacía.
%
% vacio(+Fila, +Columna).

vacio(X, Y):- not(pos(X, Y, _)).


% Predicado auxiliar pasarASN/2.
%
% Dado un número entero X, lo convierte en su respectiva notación
% s^n(0).
%
% pasarASN(+X, -Y).

pasarASN(0, 0).
pasarASN(X, s(Y)) :- X1 is X - 1, pasarASN(X1, Y).


% Predicado auxiliar pasarAN/2.
%
% Dado un número en notación s^n(0), lo convierte en su respectivo
% valor entero.
%
% pasarAN(+X, -Y).

pasarAN(0, 0).
pasarAN(s(X), Y) :- pasarAN(X, Y1), Y is Y1 + 1.


% Predicado auxiliar acomodar/3.
%
% Dado un color C y una lista de posiciones p(X, Y), devuelve una nueva lista, con esas
% posiciones más el color de la ficha del modo pos(X, Y, C), como los hechos que determinan 
% posiciones ocupadas en el tablero.
%
% acomodar(+Color, +Lista, -Salida).

acomodar(_, [], []).
acomodar(C, [p(X,Y)|XS], [pos(X,Y,C)|YS]):- acomodar(C,XS,YS).


% Predicado auxiliar contar/2.
%
% Dada una lista L, devuelve la cantidad de elementos de la lista.
%
% contar(+Lista, -Cantidad).

contar([], 0).
contar([_|Xs], s(Y)):- contar(Xs,Y).